package client.view;

import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;

import commands.SetAttributeCommand;

import core.Attribute;

/**
 * Represents a popup menu for changing the Attributes of a GameObject.
 * Each AbstractView has an AttributesPopupMenu.
 */
public class AttributesPopupMenu extends JPopupMenu {
	/**
	 * Creates an AttributesPopupMenu associated with the given AbstractView.
	 */
	public AttributesPopupMenu(AbstractView view) {
		this.view = view;
	}

	/**
	 * Refreshes the list of ModifyAttributeActions stored in the menu
	 * (needs to be called each time an Attribute is added to the GameObject)
	 */
	public void refresh()
	{
		removeAll();
		javax.swing.JMenu newAttributeMenu = new javax.swing.JMenu("New attribute");
		newAttributeMenu.add(new JMenuItem(new AddTextAttributeAction()));
		newAttributeMenu.add(new JMenuItem(new AddNumericAttributeAction()));
		super.add(newAttributeMenu);
		javax.swing.JMenu atributeMenu = new javax.swing.JMenu("Attributes");
		for (Attribute<?> a: view.getModel().getAttributes())
			atributeMenu.add(new JMenuItem(new ModifyAttributeAction(a)));
		super.add(atributeMenu);
		for (JMenuItem menuItem : menuItems)
			super.add(menuItem);
	}

	/**
	 * Adds a JMenuItem to the popup menu.
	 */
	public JMenuItem add(JMenuItem menuItem) {
		menuItems.add(menuItem);
		return super.add(menuItem);
	}

	/**
	 * Removes a JMenuItem from the popup menu.
	 */
	public void remove(JMenuItem menuItem) {
		menuItems.remove(menuItem);
		super.remove(menuItem);
	}

	private final AbstractView view;
	private final List<JMenuItem> menuItems = new LinkedList<JMenuItem>();

	private class AddTextAttributeAction extends AbstractAction
	{
		private AddTextAttributeAction() {
			super("Text...");
		}
		public void actionPerformed(ActionEvent arg0) {
			String name = JOptionPane.showInputDialog("Name:");
			if (name != null)
				try {
					view.getClient().sendCommand(new commands.NewTextAttributeCommand(name, view.getModel()));
				} catch (IOException e) {e.printStackTrace();}
		}
	}

	private class AddNumericAttributeAction extends AbstractAction {
		private AddNumericAttributeAction() {
			super("Numeric...");
		}
		public void actionPerformed(ActionEvent arg0) {
			String name = JOptionPane.showInputDialog("Name:");
			if (name != null)
				try {
					view.getClient().sendCommand(new commands.NewNumericAttributeCommand(name, view.getModel()));
				} catch (IOException e) {e.printStackTrace();}
		}
	}

	/**
	 * Represents an interface-level action to change the attribute of a GameObject.
	 * Requests a new value for the attribute via a input dialog.
	 * Creates an SetAttributeCommand and forwards it to the server.
	 */
	private class ModifyAttributeAction extends AbstractAction
	{
		private static final long serialVersionUID = 1L;
		private final Attribute<?> attr;
		private ModifyAttributeAction(Attribute<?> a) {
			super(a.toString());
			attr = a;
		}

		public void actionPerformed(ActionEvent e) {
			String value = JOptionPane.showInputDialog("Please enter the new value for the attribute", attr.getValue());
			if (value != null)
				try {
					view.getClient().sendCommand(new SetAttributeCommand(attr, value));
				} catch (IOException e1) {
					e1.printStackTrace();
				}
		}
	}
}
